#include "ServicePublisher.h"

AvahiSimplePoll* ServicePublisher::simple_poll = NULL;
AvahiEntryGroup* ServicePublisher::group = NULL;
AvahiClient* ServicePublisher::client = NULL;
UDPServer* ServicePublisher::udp_server = NULL;

void ServicePublisher::signal_handler(int signal_code) {
	if (signal_code == SIGINT) {
		Log::warning("Caught interrupt signal");
		if (client)
			avahi_client_free(client);
		if (simple_poll)
			avahi_simple_poll_free(simple_poll);
		if (udp_server)
			udp_server->shutdown(signal_code);
	}
}

void ServicePublisher::client_callback(AvahiClient *c, AvahiClientState state,
		AVAHI_GCC_UNUSED void * userdata) {
	switch (state) {
	case AVAHI_SERVER_RUNNING:
		Log::log_oss << "Registering service: " << Configuration::get_property(
				"service_name");
		Log::verbose();
		break;
	case AVAHI_CLIENT_S_REGISTERING:
	case AVAHI_CLIENT_CONNECTING:
	case AVAHI_CLIENT_S_COLLISION:
	case AVAHI_CLIENT_FAILURE:
		break;
	}
}

void ServicePublisher::group_callback(AvahiEntryGroup *g,
		AvahiEntryGroupState state, void *userdata) {
	switch (state) {
	case AVAHI_ENTRY_GROUP_ESTABLISHED:
		udp_server = UDPServer::getInstance();
		udp_server->run();
		break;
	case AVAHI_ENTRY_GROUP_COLLISION:
	case AVAHI_ENTRY_GROUP_UNCOMMITED:
	case AVAHI_ENTRY_GROUP_FAILURE:
	case AVAHI_ENTRY_GROUP_REGISTERING:
		break;
	}
}

void ServicePublisher::publish() {
	int error;
	int ret;

	struct sigaction sa;
	sa.sa_handler = &signal_handler;
	sigaction(SIGINT, &sa, NULL);

	if (!(simple_poll = avahi_simple_poll_new())) {
		Log::error("Failed to create simple poll object");
		exit(1);
	}

	client = avahi_client_new(avahi_simple_poll_get(simple_poll),
			(AvahiClientFlags) 0, client_callback, NULL, &error);
	if (!client)
		throw ServicePublisherException(string("Failed to create client: ")
				+ string(avahi_strerror(error)));

	group = avahi_entry_group_new(client, group_callback, NULL);
	if (!group)
		throw ServicePublisherException(string("Failed to create group: ")
				+ string(avahi_strerror(error)));

	ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC,
			AVAHI_PROTO_INET, (AvahiPublishFlags) 0,
			Configuration::get_property("service_name").c_str(),
			Configuration::get_property("service_type").c_str(), NULL, NULL,
			atoi(Configuration::get_property("service_port").c_str()),
			(char*) NULL);
	if (ret < 0)
		throw ServicePublisherException(string("Failed to add ")
				+ Configuration::get_property("service_type") + string(
				" service: ") + string(avahi_strerror(error)));

	ret = avahi_entry_group_commit(group);
	if (ret < 0)
		throw ServicePublisherException(
				string("Failed to commit entry group: ") + string(
						avahi_strerror(error)));

	avahi_simple_poll_loop(simple_poll);
}
